#!/usr/bin/python
# -*- coding:utf-8 -*-

'''
Created on 6 juin 2014

@author: Alexandre Neuville
'''


from datetime import datetime
from tkinter import BOTH, YES, NO, X, Y, S, N, E, W, SE, NW, LEFT, RIGHT, CENTER, TOP, BOTTOM, Menu, Listbox, Button, \
    SINGLE, END, StringVar, NONE, Scrollbar
from tkinter.messagebox import showwarning
from tkinter.simpledialog import Dialog
from tkinter.ttk import Treeview, Entry, Label, Frame

from persistence import LoggerFactory


class MainWindow(Frame):
    CMD_BUTTON_WIDTH = 11
    STD_BUTTON_WIDTH = 7

    BUTTON_PADX = "2m"
    BUTTON_PADY = "1m"
    BUTTON_PACKER_PADY = "0.5m"

    FRAME_PADX = "3m"
    FRAME_PADY = "3m"

    def __init__(self, master):
        super(MainWindow, self.__class__).__init__(self, master)
        self.__logger = LoggerFactory.getStdLogger(self)

        top_frame = Frame(self)
        top_frame.pack(side=TOP, fill=BOTH, expand=YES, anchor=N)

        bottom_frame = Frame(self)
        bottom_frame.pack(side=BOTTOM, fill=X, expand=NO, anchor=S, padx=MainWindow.FRAME_PADX,
                          pady=MainWindow.FRAME_PADY)

        button_frame = Frame(top_frame)
        button_frame.pack(side=LEFT, fill=Y, expand=NO, anchor=W, padx=MainWindow.FRAME_PADX,
                          pady=MainWindow.FRAME_PADY)

        infos_frame = Frame(top_frame)
        infos_frame.pack(side=RIGHT, fill=BOTH, expand=YES, anchor=E)

        quitButton = Button(bottom_frame, text="Quitter", command=self.close)
        quitButton.configure(width=MainWindow.STD_BUTTON_WIDTH, padx=MainWindow.BUTTON_PADX,
                             pady=MainWindow.BUTTON_PADY)
        quitButton.pack(side=RIGHT, anchor=SE)

        connectionButton = Button(button_frame, text="Profile DB", command=self.chooseActiveProfile)
        connectionButton.configure(width=MainWindow.CMD_BUTTON_WIDTH, padx=MainWindow.BUTTON_PADX,
                                   pady=MainWindow.BUTTON_PADY)
        connectionButton.pack(side=TOP, anchor=NW, pady=MainWindow.BUTTON_PACKER_PADY)

        updateButton = Button(button_frame, text="Mise à jour", command=self.updateData)
        updateButton.configure(width=MainWindow.CMD_BUTTON_WIDTH, padx=MainWindow.BUTTON_PADX,
                               pady=MainWindow.BUTTON_PADY)
        updateButton.pack(side=TOP, anchor=NW, pady=MainWindow.BUTTON_PACKER_PADY)

        disconnectButton = Button(button_frame, text="Ejecter connexion", command=self.disconnect)
        disconnectButton.configure(width=MainWindow.CMD_BUTTON_WIDTH, padx=MainWindow.BUTTON_PADX,
                                   pady=MainWindow.BUTTON_PADY)
        disconnectButton.pack(side=TOP, anchor=NW, pady=MainWindow.BUTTON_PACKER_PADY)

        self.activeProfile = StringVar()
        self.activeProfile.set("Aucun profile actif")
        Label(infos_frame, textvariable=self.activeProfile).pack(side=TOP, fill=NONE, expand=N, anchor=NW)

        self.data = data = Treeview(infos_frame, columns=("number", "user", "ip", "reqtype", "blocked", "lock", "time"),
                                    show="headings")
        data.column("number", width=100)
        data.column("user", width=100)
        data.column("ip", width=100)
        data.column("reqtype", width=100)
        data.column("blocked", width=100)
        data.column("lock", width=100)
        data.column("time", width=100)
        data.heading("number", text="ID connexion", anchor=CENTER)
        data.heading("user", text="Utilisateur", anchor=CENTER)
        data.heading("ip", text="Adresse IP", anchor=CENTER)
        data.heading("reqtype", text="Type Requête", anchor=CENTER)
        data.heading("blocked", text="Bloquée par", anchor=CENTER)
        data.heading("lock", text="Lock", anchor=CENTER)
        data.heading("time", text="Temps Activité", anchor=CENTER)
        data.pack(side=LEFT, fill=BOTH, expand=YES, anchor=E, padx=MainWindow.FRAME_PADX,
                  pady=MainWindow.FRAME_PADY)

        scrollbar = Scrollbar(infos_frame, command=self.data.yview)
        scrollbar.pack(side=LEFT, fill=Y, expand=N, anchor=E)
        self.data.configure(yscroll=scrollbar.set)

        self.pack(fill=BOTH, expand=YES)

    def close(self):
        self.master.close()

    def resetData(self):
        children = self.data.get_children("")
        for child in children:
            self.data.delete(child)
            self.__logger.debug("Child delete : %s", child)

    def addData(self, info):
        d = datetime.today() - info.time
        hours = d.seconds // 3600
        minutes = (d.seconds - hours * 3600) // 60
        seconds = d.seconds - hours * 3600 - minutes * 60
        duration = ''.join((str(hours), "h", str(minutes), "m", str(seconds), "s", str(d.microseconds)))
        iid = self.data.insert(parent="", index=0, iid=info.number, open=True,
                               values=(info.number, info.user, info.ip, info.reqtype, info.blocked, info.lock, duration))
        self.__logger.debug("Add data : %s in tree", self.data.item(iid, option="values"))
        return iid

    def disconnect(self):
        items = self.data.selection()
        self.master.disconnect(items)
        self.__logger.debug("Connections %s disconnected", items)

    def chooseActiveProfile(self):
        self.activeProfile.set(' '.join(("Profile actif :", self.master.chooseActiveProfile(),)))

    def updateData(self):
        self.master.updateData()


class MainMenu(Menu):

    def __init__(self, master):
        super(MainMenu, self.__class__).__init__(self, master)

        file = Menu(self, tearoff=0)
        file.add_command(label="Quitter", command=self.master.close)

        options = Menu(self, tearoff=0)
        options.add_command(label="Préférences", command=self.master.configuration)

        about = Menu(self, tearoff=0)
        about.add_command(label="A propos", command=self.master.about)

        self.add_cascade(label="Fichier", menu=file)
        self.add_cascade(label="Préférences", menu=options)
        self.add_cascade(label="Aide", menu=about)


class ButtonOkCancelDialog(Dialog):
    STD_BUTTON_WIDTH = 7

    BUTTON_PADX = "2m"
    BUTTON_PADY = "1m"

    FRAME_PADX = "3m"
    FRAME_PADY = "3m"

    def buttonbox(self):
        button_frame = Frame(self)
        button_frame.pack(side=BOTTOM, fill=X, expand=NO, anchor=S, padx=ButtonOkCancelDialog.FRAME_PADX,
                          pady=ButtonOkCancelDialog.FRAME_PADY)

        cancelButton = Button(button_frame, text="Annuler", command=self.cancel)
        cancelButton.configure(width=ButtonOkCancelDialog.STD_BUTTON_WIDTH, padx=ButtonOkCancelDialog.BUTTON_PADX,
                               pady=ButtonOkCancelDialog.BUTTON_PADY)
        cancelButton.pack(side=RIGHT, anchor=SE)

        okButton = Button(button_frame, text="Ok", command=self.ok)
        okButton.configure(width=ButtonOkCancelDialog.STD_BUTTON_WIDTH, padx=ButtonOkCancelDialog.BUTTON_PADX,
                           pady=ButtonOkCancelDialog.BUTTON_PADY)
        okButton.pack(side=RIGHT, anchor=SE)


class ConfigurationWindow(ButtonOkCancelDialog):
    STD_BUTTON_WIDTH = 9

    def __init__(self, master, controller):
        self.controller = controller
        self.currentSel = -1
        super(ConfigurationWindow, self.__class__).__init__(self, master)

    def body(self, master):
        self.title("Préférences")

        detail_frame = Frame(master)
        detail_frame.pack(side=RIGHT, fill=BOTH, expand=Y, anchor=E)

        Label(detail_frame, text="DSN : ").grid(row=0)
        Label(detail_frame, text="Identifiant : ").grid(row=1)
        Label(detail_frame, text="Mot de passe : ").grid(row=2)

        self.dsn = StringVar()
        self.uid = StringVar()
        self.pwd = StringVar()
        eDsn = Entry(detail_frame, textvariable=self.dsn)
        eUid = Entry(detail_frame, textvariable=self.uid)
        ePwd = Entry(detail_frame, show="*", textvariable=self.pwd)

        eDsn.grid(row=0, column=1)
        eUid.grid(row=1, column=1)
        ePwd.grid(row=2, column=1)

        list_frame = Frame(master)
        list_frame.pack(side=LEFT, fill=BOTH, expand=Y, anchor=W)

        self.list = listbox = Listbox(list_frame, selectmode=SINGLE)
        listbox.pack(side=TOP, fill=BOTH, expand=Y, anchor=N)
        listbox.bind("<<ListboxSelect>>", self.listSelection)
        self.initListbox()

        addButton = Button(list_frame, text="Ajouter", command=self.addEntry)
        addButton.configure(width=ConfigurationWindow.STD_BUTTON_WIDTH, padx=ConfigurationWindow.BUTTON_PADX,
                            pady=ConfigurationWindow.BUTTON_PADY)
        addButton.pack(side=LEFT, expand=N, anchor=S)

        delButton = Button(list_frame, text="Supprimer", command=self.delEntry)
        delButton.configure(width=ConfigurationWindow.STD_BUTTON_WIDTH, padx=ConfigurationWindow.BUTTON_PADX,
                            pady=ConfigurationWindow.BUTTON_PADY)
        delButton.pack(side=LEFT, expand=N, anchor=S)

    def initListbox(self):
        profiles = self.controller.getProfiles()
        if not profiles:
            return

        for k in sorted(profiles.keys()):
            self.list.insert(END, k)

        self.list.focus()
        if self.list.size() > 0:
            self.list.select_set(0)
            self.listSelection()

    def apply(self):
        self.saveCurrentProfile()
        self.controller.saveProfiles()

    def addEntry(self):
        top = TextEntry(self, "Information", "Nom du nouveau profile", self.controller.existProfile)
        newProfile = top.result

        self.list.insert(END, newProfile)
        sel = self.list.curselection()
        if sel:
            self.list.select_clear(sel[0])
        self.list.select_set(END)
        self.listSelection()

    def delEntry(self):
        sel = self.list.curselection()
        if not self:
            return
        s = self.list.get(sel[0])
        self.controller.deleteProfile(s)
        self.list.delete(sel[0])

        if self.list.size() > 0:
            self.list.select_set(0)
            self.listSelection()

    def listSelection(self, unusedEvent=None):
        self.saveCurrentProfile()

        self.dsn.set("")
        self.uid.set("")
        self.pwd.set("")
        sel = self.list.curselection()
        if not sel:
            self.currentSel = None
            return
        self.currentSel = sel[0]

        s = self.list.get(self.currentSel)
        p = self.controller.getProfile(s)
        if not p:
            return

        self.dsn.set(p[0])
        self.uid.set(p[1])
        self.pwd.set(p[2])

    def saveCurrentProfile(self):
        p = self.list.get(self.currentSel)
        if not p:
            self.currentSel = None
            return
        self.controller.setProfile(p, self.dsn.get(), self.uid.get(), self.pwd.get())


class TextEntry(ButtonOkCancelDialog):

    def __init__(self, master, title="", label="", validationCommand=None):
        self.validationCommand = validationCommand
        self.windowTitle = title
        self.windowLabel = label
        super(TextEntry, self.__class__).__init__(self, master)

    def body(self, master):
        self.title(self.windowTitle)
        Label(master, text=self.windowLabel).pack(side=TOP, fill=X, expand=N, anchor=NW)

        self.str = StringVar()
        e = Entry(master, textvariable=self.str)
        e.pack(side=BOTTOM, fill=X, expand=N, anchor=S)
        e.focus()

        self.result = None

    def validate(self):
        if self.validationCommand and self.validationCommand(self.str.get()):
            showwarning("Attention", ''.join(("Le profile '", self.str.get(), "' existe déjà.",)))
            return False
        return True

    def apply(self):
        self.result = self.str.get()


class ConnectionWindow(ButtonOkCancelDialog):

    def __init__(self, master, controller):
        self.controller = controller
        self.result = None
        super(ConnectionWindow, self.__class__).__init__(self, master)

    def body(self, master):
        self.list = listbox = Listbox(master, selectmode=SINGLE)
        listbox.pack(side=TOP, fill=BOTH, expand=Y, anchor=N)
        profiles = self.controller.getProfiles()
        if not profiles:
            return

        for k in sorted(profiles.keys()):
            listbox.insert(END, k)

        if listbox.size() > 0:
            listbox.select_set(0)

    def apply(self):
        sel = self.list.curselection()
        if not self:
            return
        s = self.list.get(sel)

        self.result = (s, self.controller.getProfile(s))


class AboutWindow(Dialog):
    STD_BUTTON_WIDTH = 7

    BUTTON_PADX = "2m"
    BUTTON_PADY = "1m"

    FRAME_PADX = "3m"
    FRAME_PADY = "3m"

    def buttonbox(self):
        button_frame = Frame(self)
        button_frame.pack(side=BOTTOM, fill=X, expand=NO, anchor=S, padx=AboutWindow.FRAME_PADX,
                          pady=AboutWindow.FRAME_PADY)

        cancelButton = Button(button_frame, text="Annuler", command=self.cancel)
        cancelButton.configure(width=AboutWindow.STD_BUTTON_WIDTH, padx=AboutWindow.BUTTON_PADX,
                               pady=AboutWindow.BUTTON_PADY)
        cancelButton.pack(side=BOTTOM, anchor=S)

    def body(self, master):
        Label(master, text="Nom :").grid(row=0, sticky=E)
        Label(master, text="Console SQL").grid(row=0, column=1, sticky=W)

        Label(master, text="Version :").grid(row=1, sticky=E)
        Label(master, text="0.0.1").grid(row=1, column=1, sticky=W)

        Label(master, text="Auteur :").grid(row=2, sticky=E)
        Label(master, text="AN").grid(row=2, column=1, sticky=W)
